package com.urbansquall.display
{

import flash.display.*;
import flash.utils.*;
	
/*
 * BitmapLibraryManager is good at managing BitmapDatas and BitmapLibraries.
 *
 * A BitmapLibrary is a class with a bunch of Bitmaps as its public properties.
 *
 * For example:
 *
    package
	{
	public class IconLibrary
	{
		[Embed(source='../assets/icons/001_01.png')]
		public const Icon_001_01 : Class;
		[Embed(source='../assets/icons/001_02.png')]
		public const Icon_001_02 : Class;
	}
	}
	
 * You can likely create dynamic objects and attach bitmaps at run-time
 * to create run-time libraries, but this is not the expected usage of the class.
 *
 * NOTE:
 * BitmapLibraryManager requires each Bitmap to be described by a unique name,
 * which corresponds to the property name on the library, or the name used
 * when the bitmapData is registered. This is true across libraries. If
 * you have a Icon_001_01 in Library1 and an Icon_001_01 in Library2,
 * BitmapLibraryManager will throw a runtime error if you try to register both libraries.
 */


public class BitmapLibraryManager
{
	private static var s_bitmapDataMap : Dictionary = new Dictionary( false );
	private static var s_bitmapLibraries : Array = new Array();
	
	// Disposes the BitmapData instance associated with a_name
	public static function freeBitmapData( a_name : String ) : void
	{
		if( s_bitmapDataMap[ a_name ] == null ) return;
		
		var bitmapData : BitmapData = s_bitmapDataMap[ a_name ];
		bitmapData.dispose();
		
		delete s_bitmapDataMap[ a_name ];
	}
	
	// Disposes any BitmapData instances associated with a_library
	public static function freeLibrary( a_library : Object ) : void
	{
		if( s_bitmapLibraries.indexOf( a_library ) == -1  )
		{
			throw new Error( "BitmapLibraryManager::disposeLibrary. There was no matching library for [" + a_library +"]." );
		}
		
		for( var name : String in a_library )
		{
			freeBitmapData( name );
		}
	}
	
	// Disposes all BitmapDatas currently registered
	public static function freeAll() : void
	{
		for( var key : String in s_bitmapDataMap )
		{
			var data : BitmapData = s_bitmapDataMap[ key ];
			data.dispose();
			delete s_bitmapDataMap[ key ];
		}
		
		s_bitmapLibraries.splice( 0 );
	}
	
	public static function createBitmap( a_name : String ) : Bitmap
	{
		if( s_bitmapDataMap[ a_name ] != null )
		{
			return new Bitmap( s_bitmapDataMap[ a_name ] );
		}
				
		// the bitmapData has not been loaded, so find it in one of our libraries
		for( var i : int = 0; i < s_bitmapLibraries.length; i++ )
		{
			var library : Object = s_bitmapLibraries[ i ]
			
			if( library[ a_name ] != null )
			{
				// found it
				var BitmapClass : Class = library[ a_name ];
				var bitmapData : BitmapData = ( new BitmapClass() ).bitmapData;
				insertBitmapData( a_name, bitmapData );
				return new Bitmap( bitmapData );
			}
		}
		
		trace( "BitmapLibraryManager::createBitmap. Could not find bitmapData with name [" + a_name + "]" );
		return null;
	}
		
	// Register a BitmapData even if it isn't associated with a BitmapLibrary
	public static function registerBitmapData( a_name : String, a_bitmapData : BitmapData ) : void
	{
		checkForNameCollision( a_name );
		insertBitmapData( a_name, a_bitmapData );
	}
	
	// Register an object whose public properties are BitmapDatas
	// This method will instantiate a BitmapData for all the BitmapLibrary entries
	public static function registerAndInstantiateBitmapLibrary( a_library : Object ) : void
	{
		if( s_bitmapLibraries.indexOf( a_library ) >= 0 ) return;

		registerBitmapLibrary( a_library );
		
		for( var name : String in a_library )
		{
			var BitmapClass : Class = a_library[ name ];
			try
			{
				insertBitmapData( name, ( new BitmapClass() ).bitmapData );
			}
			catch( e : Error )
			{
				throw new Error( "BitmapLibraryManager::registerAndInstantiateBitmapLibrary. Failed to instantiate library entry [" + name + "]. It most likely was not a Bitmap." );
			}
		}
	}
	
	// Register an object whose public properties are BitmapDatas
	public static function registerBitmapLibrary( a_library : Object ) : void
	{
		if( s_bitmapLibraries.indexOf( a_library ) >= 0 ) return;
		
		checkForNameCollisions( a_library );
		
		s_bitmapLibraries.push( a_library );
	}
	
	private static function checkForNameCollisions( a_newLibrary : Object ) : void
	{
		for( var name : String in a_newLibrary )
		{
			checkForNameCollision( name );
		}
	}
	
	private static function checkForNameCollision( a_name : String ) : void
	{
		for( var i : int = 0; i < s_bitmapLibraries.length; i++ )
		{
			var existingLibrary : Object = s_bitmapLibraries[ i ];
			if( existingLibrary[ a_name ] != null )
			{
				// there is a name collision between the new
				// library and the one we're trying to register
				throw new Error( "BitmapLibraryManager::checkForNameCollision. Name collision for entry [" + a_name +"] with existing library [" + existingLibrary + "]." );
			}
		}
		
		if( s_bitmapDataMap[ a_name ] != null )
		{
			throw new Error( "BitmapLibraryManager::checkForNameCollision. Name collision for entry [" + a_name +"] and existing non-library BitmapData." );
		}
	}
	
	private static function insertBitmapData( a_name : String, a_bitmapData : BitmapData ) : void
	{
		s_bitmapDataMap[ a_name ] = a_bitmapData;
	}
} // c
} // p